home *** CD-ROM | disk | FTP | other *** search
/ Die Ultimative Software-P…i Collection 1996 & 1997 / Die Ultimative Software-Pakete CD-ROM fur Atari Collection 1996 & 1997.iso / g / gnu_c / pmlsrc23.zoo / pmltests / dd2d.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-03-19  |  9.9 KB  |  419 lines

  1. /************************************************************************
  2.  *                                    *
  3.  *                N O T I C E                *
  4.  *                                    *
  5.  *            Copyright Abandoned, 1987, Fred Fish        *
  6.  *                                    *
  7.  *    This previously copyrighted work has been placed into the    *
  8.  *    public domain by the author (Fred Fish) and may be freely used    *
  9.  *    for any purpose, private or commercial.  I would appreciate    *
  10.  *    it, as a courtesy, if this notice is left in all copies and    *
  11.  *    derivative works.  Thank you, and enjoy...            *
  12.  *                                    *
  13.  *    The author makes no warranty of any kind with respect to this    *
  14.  *    product and explicitly disclaims any implied warranties of    *
  15.  *    merchantability or fitness for any particular purpose.        *
  16.  *                                    *
  17.  ************************************************************************
  18.  */
  19.  
  20. /*
  21.  *  FILE
  22.  *
  23.  *    dd2d.c   test dual double to double math functions
  24.  *
  25.  *  KEY WORDS
  26.  *
  27.  *    portable math library
  28.  *    test functions
  29.  *
  30.  *  DESCRIPTION
  31.  *
  32.  *    Tests double precision functions for the Portable Math
  33.  *    Library.  Tests those functions which expect two
  34.  *    double precision arguments and return a double.
  35.  *
  36.  *    Most of the test data in the current data file (dd2d.dat)
  37.  *    was generated using double precision FORTRAN arithmetic
  38.  *    on a Decsystem-20.
  39.  *
  40.  *    Note that the ordering of functions is important for
  41.  *    optimum error information.  Since some functions call
  42.  *    others in the library, the functions being called should
  43.  *    be tested first.  Naturally, an error in a lower level
  44.  *    function will cause propagation of errors up to higher
  45.  *    level functions.
  46.  *
  47.  *  USAGE
  48.  *
  49.  *    dd2d [-esv] [-l limit]
  50.  *
  51.  *        -e    =>    force error for each test
  52.  *                to verify error handling
  53.  *
  54.  *        -l    =>    report errors greater than
  55.  *                specified limit (default 10**-6)
  56.  *
  57.  *        -s    =>    print summary after tests
  58.  *
  59.  *        -v    =>    print each function, argument,
  60.  *                and result
  61.  *
  62.  *    Test directives are read from the standard input, which
  63.  *    may be redirected to the provided test file (dd2d.dat),
  64.  *    and any relative errors are automatically written to standard
  65.  *    output if they exceed a maximum allowable limit.
  66.  *    Each test directive has the form:
  67.  *
  68.  *        <name> <arg1> <arg2> <expected result>
  69.  *
  70.  *    Each field is separated by a one or more space character(s).
  71.  *    The first field, "name", is the name of the function
  72.  *    to test (sqrt, ln, exp, etc).  The second and third fields
  73.  *    are the arguments to use in calling the specified function.
  74.  *    The last field is the expected result.
  75.  *        
  76.  *  PROGRAMMER
  77.  *
  78.  *    Fred Fish
  79.  *    Tempe, Az 85281
  80.  *    (602) 966-8871
  81.  *
  82.  */
  83.  
  84.  
  85. #include <stdio.h>
  86. #include <math.h>
  87. #include "pml.h"
  88.  
  89. #ifdef atarist
  90. #define STDERR    stdout
  91. #else
  92. #define STDERR stderr
  93. #endif
  94.  
  95. #define MAX_ABS_ERR 1.0e-6    /* Set to catch only gross errors */
  96.  
  97. static int vflag;        /* Flag for verbose option */
  98. static int eflag;        /* Simulate an error to error printout */
  99. static int sflag;        /* Flag to show final statistics */
  100.  
  101. static double max_abs_err = MAX_ABS_ERR;
  102.  
  103. extern double atan2 ();
  104.  
  105. #ifdef max
  106. #undef min
  107. #undef max
  108.  
  109. extern double max ();
  110. extern double min ();
  111.  
  112. #endif 0
  113.  
  114. /*
  115.  *    Define all recognized test functions.  Each function
  116.  *    must have an entry in this table, where each
  117.  *    entry contains the information specified in the 
  118.  *    structure "test".
  119.  *
  120.  */
  121.  
  122. struct test {            /* Structure of each function to be tested */
  123.     char *name;            /* Name of the function to test */
  124.     double (*func)();        /* Pointer to the function's entry point */
  125.     double max_err;        /* Error accumulator for this function */
  126. };
  127.  
  128. static struct test tests[] = {    /* Table of all recognized functions */
  129.     "atan2", atan2, 0.0,    /* Arc tangent with two args */
  130.     "max", max, 0.0,        /* Maximum value */
  131.     "min", min, 0.0,        /* Minimum value */
  132.     NULL, NULL, 0.0        /* Function list end marker */
  133. };
  134.  
  135.  
  136. /*
  137.  *  FUNCTION
  138.  *
  139.  *    main   entry point for dd2d test utility
  140.  *
  141.  *  PSEUDO CODE
  142.  *
  143.  *    Begin main
  144.  *        Process any options in command line.
  145.  *        Do all tests requested by stdin directives.
  146.  *        Report final statistics (if enabled).
  147.  *    End main
  148.  *
  149.  */
  150.  
  151. main (argc, argv)
  152. int argc;
  153. char *argv[];
  154. {
  155.     options (argc, argv);
  156.     dotests (argv);
  157.     statistics ();
  158. }
  159.  
  160.  
  161. /*
  162.  *  FUNCTION
  163.  *
  164.  *    dotests   process each test from stdin directives
  165.  *
  166.  *  ERROR REPORTING
  167.  *
  168.  *    Note that in most cases, the error criterion is based
  169.  *    on relative error, defined as:
  170.  *
  171.  *        error = (result - expected) / expected
  172.  *
  173.  *    Naturally, if the expected result is zero, some
  174.  *    other criterion must be used.  In this case, the
  175.  *    absolute error is used.  That is:
  176.  *
  177.  *        error = result
  178.  *
  179.  *  PSEUDO CODE
  180.  *
  181.  *    Begin dotests
  182.  *        While a test directive is successfully read from stdin
  183.  *        Default function name to "{null}"
  184.  *        Default argument 1 to 0.0
  185.  *        Default argument 2 to 0.0
  186.  *        Default expected result to 0.0
  187.  *        Extract function name, argument and expected result
  188.  *        Lookup test in available test list
  189.  *        If no test was found then
  190.  *            Tell user that unknown function was specified
  191.  *        Else
  192.  *            Call function with argument and save result
  193.  *            If the verify flag is set then
  194.  *            Print function name, argument, and result
  195.  *            End if
  196.  *            If the expected result is not zero then
  197.  *            Compute the relative error
  198.  *            Else
  199.  *            Use the absolute error
  200.  *            End if
  201.  *            Get absolute value of error
  202.  *            If error exceeds limit or error force flag set
  203.  *            Print error notification on stderr
  204.  *            End if
  205.  *            If this error is max for given function then
  206.  *            Remember this error for summary
  207.  *            End if
  208.  *        End if
  209.  *        End while
  210.  *    End dotests
  211.  *
  212.  */
  213.  
  214.  
  215. dotests (argv)
  216. char *argv[];
  217. {
  218.     char buffer[256];        /* Directive buffer */
  219.     char function[64];        /* Specified function name */
  220.     double arg1;        /* Specified function argument 1 */
  221.     double arg2;        /* Specified function argument 2 */
  222.     double expected;        /* Specified expected result */
  223.     double result;        /* Actual result */
  224.     double error;        /* Relative or absolute error */
  225.     double abs_err;        /* Absolute value of error */
  226.     struct test *testp;        /* Pointer to function test */
  227.     struct test *lookup ();    /* Returns function test pointer */
  228.     register char *strp;    /* Pointer to next token in string */
  229.     extern char *strtok ();
  230.     extern double atof ();
  231.  
  232. #ifdef MJR
  233.     FILE * save_stdin, * re_stdin;
  234.     save_stdin = stdin;
  235.     re_stdin = freopen("dd2d.dat","r",stdin);
  236.     if( re_stdin == (FILE *)NULL ) {
  237.     exit(-33);
  238.     }
  239. #endif
  240.     while (fgets (buffer, sizeof(buffer), stdin) != NULL) {
  241.     strcpy (function, "{null}");
  242.     arg1 = 0.0;
  243.     arg2 = 0.0;
  244.     expected = 0.0;
  245.     sscanf (buffer, "%s %le %le %le", function, &arg1, &arg2, &expected);
  246.         testp = lookup (function);
  247.         if (testp == NULL) {
  248.             fprintf (STDERR, "%s: unknown function \"%s\".\n",
  249.             argv[0], function);
  250.         } else {
  251.         result = (*testp -> func)(arg1, arg2);
  252.         if (vflag) {
  253.             printf ("%s(%le,%le) = %30.23le.\n",
  254.         function, arg1, arg2, result);
  255.         }
  256.         if (expected != 0.0) {
  257.             error = (result - expected) / expected;
  258.         } else {
  259.             error = result;
  260.         }
  261.         if (error < 0.0) {
  262.         abs_err = -error;
  263.         } else {
  264.         abs_err = error;
  265.         }
  266.             if ((abs_err > max_abs_err) || eflag) {
  267.         fprintf (STDERR, "%s: error in \"%s\"\n", argv[0], function);
  268.         fprintf (STDERR, "\targument 1\t%25.20le\n", arg1);
  269.         fprintf (STDERR, "\targument 2\t%25.20le\n", arg2);
  270.         fprintf (STDERR, "\tresult\t\t%25.20le\n", result);
  271.         fprintf (STDERR, "\texpected\t%25.20le\n", expected);
  272.             }
  273.         if (abs_err > testp -> max_err) {
  274.             testp -> max_err = abs_err;
  275.         }
  276.         }
  277.     }
  278. #ifdef MJR
  279.     fclose( re_stdin );
  280. #endif
  281. }
  282.  
  283.  
  284. /*
  285.  *  FUNCTION
  286.  *
  287.  *    options   process command line options
  288.  *
  289.  *  PSEUDO CODE
  290.  *
  291.  *    Begin options
  292.  *        Reset all flags to FALSE by default
  293.  *        Initialize flag argument scan pointer
  294.  *        If there is a second command line argument then
  295.  *        If the argument specifies flags then
  296.  *            While there is an unprocessed flag
  297.  *            Switch on flag
  298.  *            Case "force error flag":
  299.  *                Set the "force error" flag
  300.  *                Break switch
  301.  *            Case "print summary":
  302.  *                Set "print summary" flag
  303.  *                Break switch
  304.  *            Case "verbose":
  305.  *                Set "verbose" flag
  306.  *                Break switch
  307.  *            Default:
  308.  *                Tell user unknown flag
  309.  *                Break switch
  310.  *            End switch
  311.  *            End while
  312.  *        End if
  313.  *        End if
  314.  *    End options
  315.  *
  316.  */
  317.  
  318.  
  319. options (argc, argv)
  320. int argc;
  321. char *argv[];
  322. {
  323.     register int flag;
  324.     extern int getopt ();
  325.     extern char *optarg;
  326.  
  327.     eflag = sflag = vflag = FALSE;
  328.     while ((flag = getopt (argc, argv, "#:el:sv")) != EOF) {
  329.     switch (flag) {
  330.         case '#':
  331.         break;
  332.         case 'e':
  333.         eflag = TRUE;
  334.         break;
  335.         case 'l':
  336.             sscanf (optarg, "%le", &max_abs_err);
  337.         break;
  338.         case 's':
  339.         sflag = TRUE;
  340.         break;
  341.         case 'v':
  342.         vflag = TRUE;
  343.         break;
  344.     }
  345.     }
  346. }
  347.  
  348.  
  349. /*
  350.  *  FUNCTION
  351.  *
  352.  *    loopup   lookup test in known test list
  353.  *
  354.  *  DESCRIPTION
  355.  *
  356.  *    Given the name of a desired test, looks up the test
  357.  *    in the known test list and returns a pointer to the
  358.  *    test structure.
  359.  *
  360.  *    Since the table is so small we simply use a linear
  361.  *    search.
  362.  *
  363.  *  PSEUDO CODE
  364.  *
  365.  *    Begin lookup
  366.  *        For each known test
  367.  *        If the test's name matches the desired test name
  368.  *            Return pointer to the test structure
  369.  *        End if
  370.  *        End for
  371.  *    End lookup
  372.  *
  373.  */
  374.  
  375. struct test *lookup (funcname)
  376. char *funcname;
  377. {
  378.     struct test *testp;
  379.     struct test *rtnval;
  380.  
  381.     rtnval = (struct test *) NULL;
  382.     for (testp = tests; testp -> name != NULL && rtnval == NULL; testp++) {
  383.     if (!strcmp (testp -> name, funcname)) {
  384.         rtnval = testp;
  385.      }
  386.     }
  387.     return (rtnval);
  388. }
  389.  
  390.  
  391. /*
  392.  *  FUNCTION
  393.  *
  394.  *    statistics   print final statistics if desired
  395.  *
  396.  *  PSEUDO CODE
  397.  *
  398.  *    Begin statistics
  399.  *        If a final statistics (summary) is desired then
  400.  *        For each test in the known test list
  401.  *            Print the maximum error encountered
  402.  *        End for
  403.  *        End if
  404.  *    End statistics
  405.  *
  406.  */
  407.  
  408. statistics ()
  409. {
  410.     struct test *tp;
  411.  
  412.     if (sflag) {
  413.         for (tp = tests; tp -> name != NULL; tp++) {
  414.         printf ("%s:\tmaximum relative error %le\n", 
  415.             tp -> name, tp -> max_err);
  416.     }
  417.     }
  418. }
  419.